#pragma once

#include<iostream>
#include<unistd.h>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
#include<ctime>
#include<cstring>

using namespace std;

const int n = 5;

template<class T>
class RRQueue
{
public:
  RRQueue(int num = n)
    :_capacity(num)
    ,_data(num)
  {
    sem_init(&_data_sem,0,0);
    sem_init(&_space_sem,0,num);
    _p_step = _c_step = 0;

    pthread_mutex_init(&_consumer,nullptr);
    pthread_mutex_init(&_productor,nullptr);
  } 

  void P(sem_t& s)
  {
    sem_wait(&s);
  }

  void V(sem_t& s)
  {
    sem_post(&s);
  }

  void Lock(pthread_mutex_t& mutex)
  {
    pthread_mutex_lock(&mutex);
  }

  void UnLock(pthread_mutex_t& mutex)
  {
    pthread_mutex_unlock(&mutex);
  }

  void push(const T& key)
  {
    P(_space_sem);//申请信号量，判断有没有空间
    Lock(_productor);//加锁的原因是保护临界区，防止多个线程一起往_p_step存数据，导致数据重叠而丢失
    _data[_p_step++] = key;
    _p_step %= _capacity;
    UnLock(_productor);
    V(_data_sem);
  }

  void pop(T& key)
  {
    P(_data_sem);
    Lock(_consumer);
    key = _data[_c_step++];
    _c_step %= _capacity;
    UnLock(_consumer);
    V(_space_sem);
  }

  ~RRQueue()
  {
    sem_destroy(&_data_sem);
    sem_destroy(&_space_sem);

    pthread_mutex_destroy(&_consumer);
    pthread_mutex_destroy(&_productor);
  }
private:
  vector<T> _data;
  int _capacity;
  sem_t _data_sem;
  sem_t _space_sem;
  int _p_step;
  int _c_step;
  pthread_mutex_t _consumer;
  pthread_mutex_t _productor;
};
